import { createPool } from "mysql";
/**
 * 数据库操作对象
 *
 */
class MySql {
  /**
   * 创建数据库操作对象
   *
   * mysql://username:password@host:port/database?charset=utf8
   *
   * {host: 'host', user: 'username', password: 'password', database: 'database'}
   *
   * @param {string | PoolOptions} config
   */
  constructor(config) {
    // conn 连接池对象
    this.conn = createPool(config);
  }

  query(sql, ...values) {
    // 标签模板调用方式
    if (Array.isArray(sql)) {
      sql = sql.join("?");
    } else {
      values =
        values.length == 1 && Array.isArray(values[0]) ? values[0] : values;
    }
    return new Promise((resolve, reject) => {
      this.conn.query(sql, values, (err, results, fields) => {
        // result: [{... record}, {... record}, ...]
        if (err) reject(err);
        else resolve([results, fields]);
      });
    });
  }
  /**
   * 适合执行返回单条记录的 select 语句
   *
   * @param {string} sql 查询语句 select
   * @param {Array<any>} values 查询语句参数
   * @returns {Promise<any>}
   */
  async findOne(sql, ...values) {
    const [[one]] = await this.query(sql, ...values);
    return one;
  }

  /**
   * 适合执行返回多条记录(数组)的 select 语句
   *
   * @param {string} sql 查询语句 select
   * @param {Array<any>} values 查询语句参数
   * @returns {Promise<Array<any>>}
   */
  async findAll(sql, ...values) {
    const [results] = await this.query(sql, ...values);
    return results;
  }
  /**
   * 执行 insert 语句
   *
   * @param {string} sql insert 语句
   * @param {Array<any>} values insert 语句参数
   * @returns {Promise<number>}
   */
  async insert(sql, ...values) {
    const [results] = await this.query(sql, ...values);
    return results.insertId;
  }

  /**
   * 执行 update, delete 等无返回值的 sql 语句
   *
   * @param {string} sql update, delete 语句
   * @param {Array<any>} values update, delete 语句参数
   * @returns {Promise<void>}
   */
  async run(sql, ...values) {
    await this.query(sql, ...values);
  }

  close() {
    return new Promise((resolve, reject) => {
      this.conn.end((err) => {
        if (err) reject(err);
        else resolve();
      });
    });
  }
}

const { DB_URL } = process.env;
const db = new MySql(DB_URL);

export default db;
